﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Linq.Expressions;

namespace Xceed.Silverlight.Data
{
  public class PredicateBuilder
  {
    #region Constructor

    public PredicateBuilder( FilterExpressionBase expression )
    {
      m_expression = expression;
    }

    #endregion

    public Func<T, bool> ToPredicate<T>()
    {
      return PredicateBuilder.ToPredicate<T>( m_expression, typeof( T ), false, null );
    }

    internal Func<T, bool> ToPredicate<T>( 
      Type dataItemUnderlyingType,
      Func<string, Type> getDataMemberType )
    {
      return PredicateBuilder.ToPredicate<T>( 
               m_expression, 
               dataItemUnderlyingType, 
               true,
               getDataMemberType );
    }

    internal Func<object, bool> ToPredicate( Type itemType )
    {
      if( m_expression == null )
        return PredicateBuilder.DefaultPredicate<object>;

      ParameterExpression parameter = Expression.Parameter( typeof( object ), null );

      // Create an expression of type Func<"itemType", bool>.
      ExpressionBuilder eb = new ExpressionBuilder( m_expression );
      Expression innerPredicate = eb.ToExpression( itemType );

      if( innerPredicate == null )
        return PredicateBuilder.DefaultPredicate<object>;

      Expression innerPredicateParameter = parameter;
      if( innerPredicateParameter.Type != itemType )
      {
        innerPredicateParameter = Expression.Convert( innerPredicateParameter, itemType );
      }

      Expression innerPredicateInvoke = Expression.Invoke( innerPredicate, innerPredicateParameter );
      LambdaExpression outerPredicate = Expression.Lambda( innerPredicateInvoke, parameter );

      return ( Func<object, bool> )outerPredicate.Compile();
    }

    private static Func<T, bool> ToPredicate<T>(
      FilterExpressionBase expression,
      Type dataItemUnderlyingType,
      bool isRawDataItem,
      Func<string, Type> getDataMemberType )
    {
      if( expression == null )
        return PredicateBuilder.DefaultPredicate<T>;

      ExpressionBuilder eb = new ExpressionBuilder( expression );
      Expression<Func<T, bool>> predicate;

      // Create a predicate that gets the object's property value through the
      // RawDataItem class.
      if( isRawDataItem )
      {
        predicate = eb.ToExpression<T>( dataItemUnderlyingType, getDataMemberType );
      }
      // Create a predicate that gets the object's property value directly from
      // the object.
      else
      {
        predicate = eb.ToExpression<T>();
      }

      if( predicate == null )
        return PredicateBuilder.DefaultPredicate<T>;

      return predicate.Compile();
    }

    private static bool DefaultPredicate<T>( T item )
    {
      return true;
    }

    #region Private Fields

    private readonly FilterExpressionBase m_expression; //null

    #endregion

    #region ExpressionBuilder Nested Type

    private class ExpressionBuilder : PredicateExpressionBuilder
    {
      internal ExpressionBuilder( FilterExpressionBase expression )
        : base( expression )
      {
      }

      protected override Expression<Func<T, bool>> CreateTautology<T>()
      {
        return null;
      }
    }

    #endregion
  }
}
